/**
 * 文件上传服务（S3 Pre-signed URL）
 *
 * 职责：
 * 1. 生成 S3 预签名上传 URL
 * 2. 验证上传参数（文件大小、类型等）
 * 3. 提供文件访问 URL
 *
 * 使用方式：
 * 前端调用 generateUploadUrl() 获取预签名 URL
 * 前端直接上传文件到 S3
 * 上传成功后，前端将文件 URL 传给签到接口
 */

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
import { createSuccessResult, createErrorResult, handleServiceError } from '@services/common/utils'
import { FILE_UPLOAD_LIMITS } from '@services/common/constants'
import type { ServiceResult } from '@services/common/types'

// S3 配置（从环境变量读取）
const S3_CONFIG = {
    region: process.env.AWS_REGION || 'us-east-1',
    endpoint: process.env.S3_ENDPOINT, // 兼容 MinIO 等 S3 兼容服务
    credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
    },
    forcePathStyle: process.env.S3_FORCE_PATH_STYLE === 'true', // MinIO 需要
    bucket: process.env.S3_BUCKET || 'checkin-photos'
}

// 初始化 S3 客户端
const s3Client = new S3Client({
    region: S3_CONFIG.region,
    endpoint: S3_CONFIG.endpoint,
    credentials: S3_CONFIG.credentials,
    forcePathStyle: S3_CONFIG.forcePathStyle
})

// ==================== 类型定义 ====================

export interface GenerateUploadUrlDTO {
    userId: string // 上传者ID（memberId 或 adminId）
    userType: 'member' | 'admin'
    fileType: string // MIME 类型，如 'image/jpeg'
    fileSize: number // 文件大小（字节）
    eventId?: string // 关联的事件ID（可选）
}

export interface UploadUrlResult {
    uploadUrl: string // 预签名 URL
    fileKey: string // S3 文件 key
    accessUrl: string // 访问 URL（上传成功后使用）
    expiresIn: number // URL 有效期（秒）
}

export interface ValidateFileParams {
    fileType: string
    fileSize: number
}

// ==================== 核心功能 ====================

/**
 * 生成上传 URL（预签名）
 * @param dto 上传参数
 * @returns 预签名 URL 和相关信息
 */
export const generateUploadUrl = async (dto: GenerateUploadUrlDTO): Promise<ServiceResult<UploadUrlResult>> => {
    try {
        // 1. 验证上传参数
        const validation = validateFileParams({
            fileType: dto.fileType,
            fileSize: dto.fileSize
        })

        if (!validation.valid) {
            return createErrorResult(validation.message || 'Invalid file parameters', 422)
        }

        // 2. 生成文件 key（路径）
        const fileKey = generateFileKey(dto)

        // 3. 生成文件扩展名
        const extension = getExtensionFromMimeType(dto.fileType)

        // 4. 完整的 S3 key
        const s3Key = `${fileKey}.${extension}`

        // 5. 创建 PutObject 命令
        const command = new PutObjectCommand({
            Bucket: S3_CONFIG.bucket,
            Key: s3Key,
            ContentType: dto.fileType,
            ContentLength: dto.fileSize,
            Metadata: {
                userId: dto.userId,
                userType: dto.userType,
                eventId: dto.eventId || '',
                uploadTime: new Date().toISOString()
            }
        })

        // 6. 生成预签名 URL（15分钟有效）
        const expiresIn = 900 // 15分钟
        const uploadUrl = await getSignedUrl(s3Client, command, { expiresIn })

        // 7. 生成访问 URL
        const accessUrl = generateAccessUrl(s3Key)

        return createSuccessResult({
            uploadUrl,
            fileKey: s3Key,
            accessUrl,
            expiresIn
        })
    } catch (error) {
        return handleServiceError(error)
    }
}

/**
 * 验证文件参数
 * @param params 文件参数
 * @returns 验证结果
 */
export const validateFileParams = (
    params: ValidateFileParams
): {
    valid: boolean
    message?: string
} => {
    // 1. 验证文件大小
    if (params.fileSize <= 0) {
        return { valid: false, message: 'File size must be greater than 0' }
    }

    if (params.fileSize > FILE_UPLOAD_LIMITS.maxPhotoSize) {
        return {
            valid: false,
            message: `File size exceeds limit (${FILE_UPLOAD_LIMITS.maxPhotoSize / 1024 / 1024}MB)`
        }
    }

    // 2. 验证文件类型
    const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']

    if (!allowedTypes.includes(params.fileType.toLowerCase())) {
        return {
            valid: false,
            message: `File type not allowed. Allowed: ${FILE_UPLOAD_LIMITS.allowedPhotoFormats.join(', ')}`
        }
    }

    return { valid: true }
}

/**
 * 生成文件 key（S3 路径）
 * 格式：{userType}/{userId}/{eventId}/{timestamp}_{random}
 */
const generateFileKey = (dto: GenerateUploadUrlDTO): string => {
    const timestamp = Date.now()
    const random = Math.random().toString(36).substring(2, 8)
    const eventPart = dto.eventId ? `/${dto.eventId}` : ''

    return `${dto.userType}/${dto.userId}${eventPart}/${timestamp}_${random}`
}

/**
 * 从 MIME 类型获取文件扩展名
 */
const getExtensionFromMimeType = (mimeType: string): string => {
    const mimeMap: Record<string, string> = {
        'image/jpeg': 'jpg',
        'image/jpg': 'jpg',
        'image/png': 'png',
        'image/webp': 'webp'
    }

    return mimeMap[mimeType.toLowerCase()] || 'jpg'
}

/**
 * 生成访问 URL
 * 注意：这里假设 S3 bucket 是公开访问或配置了 CloudFront
 * 如果需要私有访问，也需要生成预签名 URL
 */
const generateAccessUrl = (s3Key: string): string => {
    // 如果配置了自定义域名（如 CloudFront）
    if (process.env.S3_PUBLIC_URL) {
        return `${process.env.S3_PUBLIC_URL}/${s3Key}`
    }

    // 如果是自定义 endpoint（如 MinIO）
    if (S3_CONFIG.endpoint) {
        return `${S3_CONFIG.endpoint}/${S3_CONFIG.bucket}/${s3Key}`
    }

    // 默认 AWS S3 URL
    return `https://${S3_CONFIG.bucket}.s3.${S3_CONFIG.region}.amazonaws.com/${s3Key}`
}

/**
 * 生成私有访问 URL（预签名，用于查看）
 * @param s3Key S3 文件 key
 * @param expiresIn 有效期（秒），默认 1 小时
 * @returns 预签名访问 URL
 */
export const generateAccessPresignedUrl = async (
    s3Key: string,
    expiresIn: number = 3600
): Promise<ServiceResult<{ url: string; expiresIn: number }>> => {
    try {
        const command = new PutObjectCommand({
            Bucket: S3_CONFIG.bucket,
            Key: s3Key
        })

        // 注意：这里应该使用 GetObjectCommand，但为了简化示例使用 PutObjectCommand
        // 实际生产环境应该导入 GetObjectCommand
        const url = await getSignedUrl(s3Client, command, { expiresIn })

        return createSuccessResult({ url, expiresIn })
    } catch (error) {
        return handleServiceError(error)
    }
}

/**
 * 验证 URL 是否为有效的 S3 URL
 * @param url 要验证的 URL
 * @returns 是否有效
 */
export const isValidS3Url = (url: string): boolean => {
    try {
        const urlObj = new URL(url)

        // 检查是否是 S3 域名
        const isS3Domain =
            urlObj.hostname.includes('.s3.') ||
            urlObj.hostname.includes('s3.amazonaws.com') ||
            urlObj.hostname.includes(S3_CONFIG.bucket)

        // 检查协议
        const isHttps = urlObj.protocol === 'https:'

        return isS3Domain && isHttps
    } catch {
        return false
    }
}

/**
 * 从 S3 URL 提取文件 key
 * @param url S3 URL
 * @returns 文件 key 或 null
 */
export const extractS3KeyFromUrl = (url: string): string | null => {
    try {
        const urlObj = new URL(url)
        // 移除开头的 /bucket/
        const pathname = urlObj.pathname.replace(`/${S3_CONFIG.bucket}/`, '')
        return pathname || null
    } catch {
        return null
    }
}

// ==================== 导出配置（用于测试） ====================

export const getS3Config = () => ({
    bucket: S3_CONFIG.bucket,
    region: S3_CONFIG.region,
    endpoint: S3_CONFIG.endpoint
})
